<!DOCTYPE html>

<html>
<head>

    <title>Mining Key Script</title>

    <style>
        html {
            font-family: Arial, Helvetica, sans-serif;
        }
        .roundedWrapper {
            border: 1px solid #d1d1d1;
            border-radius: 5px;
            padding: 10px;
            margin: 10px;
        }

        .heading{
            font-weight: bold;
            margin: 10px 0px 5px 0
        }

        .orSeperator{
            text-align: center;
            font-style: italic;
            font-size: 0.9em;
            color: grey;
        }

        .keyStarOptions {
            float: left;
            font-size: 1.7em;
            margin: 4px;
            padding-right: 10px;
        }

        #processKeyWarning {
            display: none;
        }

        #printFrame {
            display: none;
        }

        #dataHolder {
            display: none;
        }

        input[type=text] {
            width: 550px;
            font-family: "Lucida Console", Monaco, monospace
        }

        input[type=text][readonly] {
            background-color: #f5f5f5;
        }

        .warning {
            color: #920505;
        }

        #importInstructions {
            display: none;
        }

        #coinSelect, .coinName {
            text-transform: capitalize;
        }

    </style>

</head>

<body>


<div id="keyStartHolder">
    <h4>Mining key generation or input options:</h4>

    <div class="roundedWrapper">
        <div class="keyStarOptions">1)</div>
        <div>Create new private key</div>
        <button id="generate">Generate</button>
    </div>
    <div class="orSeperator">- or- </div>
    <div class="roundedWrapper">
        <div class="keyStarOptions">2)</div>
        <div>Import existing private key</div>
        <input type="file" id="import" name="import"/>
    </div>
    <div class="orSeperator">- or- </div>
    <div class="roundedWrapper">
        <div class="keyStarOptions">3)</div>
        <div>Input private key hex</div>
        <input type="text" id="privateKeyInput">
        <button id="processKeyInput">Process</button>
        <div class="warning" id="processKeyWarning">Private key must be 64 hexadecimal characters</div>
    </div>
</div>

<div id="dataHolder">

    <button id="returnKeyStart">Go back to <i>Key input or generation</i></button>

    <div class="roundedWrapper">
        <div class="heading warning">NO NOT LOSE THIS PRIVATE KEY. Any coins mined using this public key can
            only be controlled with this private key.</div>

        <div class="heading">Private key: <br><input type="text" width="550px" readonly id="privateKeyHex"></div>
        <div class="heading">Key for mining (hashed public key): <br><input type="text" width="550px" readonly id="miningKey"></div>

        <p>
            An address for any type of coin can be derived from this mining key - and each of those coin address
            can only be controlled by this private key.
        </p>

    </div>

    <div class="roundedWrapper">
        <div class="heading">Backup your private key</div>
        <table>
            <tr>
                <td>Step 1)</td>
                <td><a id="download" download="private_key.txt">
                    <button>Save key to file</button>
                </a></td>
            </tr>
            <tr>
                <td>Step 2)</td>
                <td>
                    <button id="print" href="#">Print key to paper</button>
                </td>
            </tr>
        </table>
    </div>

    <div class="roundedWrapper">
        <div class="heading">Coin formatted keys</div>
        <select id="coinSelect">
            <option value="">Select a coin</option>
            {{ for(var coin in it.coins) { }}
            <option value="{{=it.coins[coin]}}">{{=coin}}</option>
            {{ } }}
        </select>

        <div class="heading">Public <span class="coinName"></span> address</div>
        <input type="text" id="coinAddress" readonly>

        <div class="heading">Private <span class="coinName"></span> key in wallet import format</div>
        <input type="text" id="coinWIF" readonly>

        <div id="importInstructions">
            <div class="heading">How to import your private key for <span class="coinName"></span>:</div>
            <ol>
                <li>Open your <span class="coinName"></span> wallet app</li>
                <li>Go to <b>Help</b> -> click <b>Debug window</b> -> click <b>Console</b> tab</li>
                <li>Enter the following command: <b>importprivkey <span id="instructionPrivKey"></span></b></li>
            </ol>
        </div>

    </div>


</div>


<iframe id="printFrame" name="printFrame"></iframe>

<script>

function notifyNoob(feature) {
    alert("Your (crap) web browser doesn't support the HTML5 " + feature + ' feature. This page will not functional properly until you upgrade to a modern browser.');
}


window.crypto = window.crypto || window.msCrypto;

if (!crypto)
    notifyNoob('Cryptography API');
else if (!File)
    notifyNoob('File');
else if (!FileReader)
    notifyNoob('FileReader');
else if (!Blob)
    notifyNoob('Blob');
else if (!Uint8Array)
    notifyNoob('Typed Arrays')
else if (!document.querySelectorAll)
    notifyNoob('Document Query Selector');
else if (typeof document.createElement('a').download === 'undefined')
    notifyNoob('Download Attribute');


Array.prototype.forEach.call(document.querySelectorAll('input[type=text][readonly]'), function (el) {
    el.addEventListener('click', function () {
        this.select();
    }, false);
});


function isValidPrivateKey(str) {
    if (str.length !== 64)
        return false;

    str = str.toLowerCase();

    var hexChars = '0123456789abcdef';
    for (var i = 0; i < str.length; i++) {
        if (hexChars.indexOf(str[i]) === -1) {
            return false;
        }
    }
    return true;
}

function $id(id) {
    return document.getElementById(id);
}

function $class(cl) {
    return document.getElementsByClassName(cl);
}

var wallet;

$id('returnKeyStart').addEventListener('click', function () {
    $id('import').value = null;
    $id('privateKeyInput').value = '';
    $id('keyStartHolder').style.display = 'block';
    $id('dataHolder').style.display = 'none';
    $id('processKeyWarning').style.display = 'none';
});

$id('coinSelect').addEventListener('keyup', function () {
    populateCoinData();
});

$id('coinSelect').addEventListener('change', function () {
    populateCoinData();
});

$id('print').addEventListener('click', function () {
    var printFrame = $id('printFrame');
    var printFrameDoc = printFrame.contentDocument || printFrame.contentWindow.document;
    printFrameDoc.body.innerHTML = '';
    printFrameDoc.write('Private key hex data:<br> ' + wallet.getPrivateKeyHex() + '<script> function printPage(){ print() } <\/script>');
    printFrame.contentWindow.focus();
    printFrame.contentWindow.printPage();
}, false);


$id('generate').addEventListener('click', function () {
    wallet = new Wallet();
    populatePageData();
}, false);


$id('import').addEventListener('change', function (evt) {

    var notifyInvalidFile = function (msg) {
        alert('The selected file is not valid, must be a text file containing 64 hexadecimal characters');
    };

    var file = evt.target.files[0];
    var reader = new FileReader();
    reader.addEventListener('load', function (evt) {

        var str = evt.target.result;
        if (!isValidPrivateKey(str))
            return notifyInvalidFile();

        wallet = new Wallet({privateKey: str});
        populatePageData();
    });
    if (file)
        reader.readAsText(file);
}, false);


var tryInputParse = function () {
    if (isValidPrivateKey(this.value)) {
        wallet = new Wallet({privateKey: this.value});
        populatePageData();
    }
};
$id('privateKeyInput').addEventListener('paste', tryInputParse);
$id('privateKeyInput').addEventListener('keyup', tryInputParse);
$id('processKeyInput').addEventListener('click', function () {
    if (!isValidPrivateKey(this.value)) {
        $id('processKeyWarning').style.display = 'block';
        return;
    }
    tryInputParse();
});



function populatePageData() {

    $id('keyStartHolder').style.display = 'none';

    var privateKeyHex = wallet.getPrivateKeyHex();

    $id('privateKeyHex').value = privateKeyHex;
    $id('miningKey').value = wallet.getMiningKey();

    var keyBlob = new Blob([privateKeyHex], {type: 'text/plain'});
    var keyBlobURL = window.URL.createObjectURL(keyBlob);
    $id('download').setAttribute('href', keyBlobURL);

    $id('dataHolder').style.display = 'block';

    populateCoinData();
}


function populateCoinData() {
    var coinSelectEl = $id('coinSelect');
    var val = coinSelectEl.options[coinSelectEl.selectedIndex].value;
    if (!val) {
        $id('coinAddress').value = '(select a coin)';
        $id('coinWIF').value = '(select a coin)';
        Array.prototype.forEach.call($class('coinName'), function (el) {
            el.innerText = 'coin';
        });
        $id('importInstructions').style.display = 'none';
    }
    else {
        var bytes = val.split(',');
        $id('coinAddress').value = wallet.getAddress(parseInt(bytes[0]));
        $id('coinWIF').value = $id('instructionPrivKey').innerText = wallet.getPrivateKeyWiF(parseInt(bytes[1]));
        Array.prototype.forEach.call($class('coinName'), function (el) {
            el.innerText = coinSelectEl.options[coinSelectEl.selectedIndex].innerText;
        });
        $id('importInstructions').style.display = 'block';
    }
}


(function (global) {

    var util = {
        joinByteArrays: function (arr1, arr2) {
            var newArr = new Uint8Array(arr1.byteLength + arr2.byteLength);
            newArr.set(arr1, 0);
            newArr.set(arr2, arr1.byteLength);
            return newArr;
        },
        bigIntegerToByteArray: function (bigInt) {
            return util.hexToByteArray(bigInt.toString(16));
        },
        secureRandom: function (count) {
            var nativeArr = new Uint8Array(count);
            window.crypto.getRandomValues(nativeArr);
            for (var i = 0; i < nativeArr.length; i++) {
                if (nativeArr[i] == 0)
                    nativeArr[i] = Math.floor(Math.random() * (255 - 1 + 1)) + 255;
            }
            return nativeArr;
        },
        byteArrayToHex: function (arr) {
            var hexEncodeArray = '0123456789abcdef';
            var s = '';
            for (var i = 0; i < arr.length; i++) {
                var code = arr[i];
                s += hexEncodeArray[code >>> 4];
                s += hexEncodeArray[code & 0x0F];
            }
            return s;
        },
        byteArrayToBase58: function (arr) {
            var intData = BigInteger(util.byteArrayToHex(arr), 16);
            var digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
            var result = '';
            var data = util.bigIntegerToByteArray(intData);
            var BIG58 = BigInteger("58");
            while (intData.signum() > 0) {
                var parts = intData.divideAndRemainder(BIG58);
                intData = parts[0];
                result = digits[parts[1]] + result;
            }
            for (var i = 0; i < arr.length && arr[i] === 0; i++) {
                result = '1' + result;
            }
            return result;
        },
        hexToByteArray: function (hexString) {
            var bytes = new Uint8Array(hexString.length / 2);
            for (var i = 0; i < bytes.length; i++) {
                bytes[i] = parseInt(hexString.substr(i * 2, 2), 16);
            }
            return bytes;
        }
    };


    function Wallet(options) {
        options = options || {};
        this.privateKey = options.privateKey ? util.hexToByteArray(options.privateKey) : util.secureRandom(32);
        this.privateKeyHex = util.byteArrayToHex(this.privateKey);
        this.privateKeyInt = BigInteger(this.privateKeyHex, 16);
        this.compressed = !!options.compressed;
        this.X9ECParamsName = options.X9ECParamsName || 'secp256k1';
        this.ecurve = new EllipticCurve(this.X9ECParamsName, this.privateKeyInt);
    }

    Wallet.prototype = {
        getPublicKey: function () {
            var point = this.ecurve.getPoint();
            var x = point.getX().x;
            var y = point.getY().x;

            console.log('x ' + x.toString());
            console.log('y ' + y.toString());

            var enc = util.bigIntegerToByteArray(x);
            console.log(enc);

            var prefix = new Uint8Array([this.compressed ? (y.isEven() ? 2 : 3) : 4]);

            var pubKey = util.joinByteArrays(prefix, enc);

            if (!this.compressed)
                pubKey = util.joinByteArrays(pubKey, util.bigIntegerToByteArray(y));

            return pubKey;
        },
        getMiningKeyBytes: function () {
            var pubKey = this.getPublicKey();
            var pubKeySha = sha256(pubKey);
            var pubKeyRipdm = ripemd160(pubKeySha);
            return new Uint8Array(pubKeyRipdm);
        },
        getMiningKey: function () {
            return util.byteArrayToHex(this.getMiningKeyBytes());
        },
        getPrivateKeyHex: function () {
            return this.privateKeyHex;
        },
        getPrivateKeyWiF: function (versionByte) {
            var privKeyVersionByte = util.joinByteArrays(new Uint8Array([versionByte]), this.privateKey);
            var privKeySha = sha256(privKeyVersionByte);
            var privKeySha2nd = sha256(privKeySha);
            var checksum = privKeySha2nd.subarray(0, 4);
            var privKeyBytes = util.joinByteArrays(privKeyVersionByte, checksum);
            return util.byteArrayToBase58(privKeyBytes);
        },
        getAddress: function (versionByte) {
            var pukKeyRipmd = this.getMiningKeyBytes();
            var pukKeyRipmdVersionByte = util.joinByteArrays(new Uint8Array([versionByte]), pukKeyRipmd);
            var pubKeySha2nd = sha256(pukKeyRipmdVersionByte);
            var pubKeySha3rd = sha256(pubKeySha2nd);
            var checksum = pubKeySha3rd.subarray(0, 4);
            var addressBytes = util.joinByteArrays(pukKeyRipmdVersionByte, checksum);
            return util.byteArrayToBase58(addressBytes);
        }
    };

    global['Wallet'] = Wallet;

})(this);


// Dependencies: EllipticCurve, Sha256, Ripemd160, BigInteger

(function (global) {

    /*
     Lightweight Elliptic curve cryptography module containing what is need to generate public key from private key

     Requires Tom Wu's javascript big number library https://github.com/andyperlitch/jsbn

     Created by Matthew Little, 2014

     Code based on EC code from bitcoin-js which is based off BouncyCastle's Java EC code


     Supports the X9ECParameters used for majority for cryptocurrencies (secp256k1 & secp256r1)

     */


    function EllipticCurve(X9ECName, privateKeyBignum) {

        function fromHex(s) {
            return new BigInteger(s, 16);
        }

        function X9ECParameters(curve, g, n, h) {
            this.curve = curve;
            this.g = g;
            this.n = n;
            this.h = h;
        }

        var X9ECTypes = {
            secp256k1: function () {
                var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
                var a = BigInteger.ZERO;
                var b = fromHex("7");

                var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
                var h = BigInteger.ONE;
                var curve = new ECCurve(p, a, b);

                var x = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798");
                var y = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
                var g = new ECPoint(curve,
                        curve.fromBigInteger(x),
                        curve.fromBigInteger(y));

                return new X9ECParameters(curve, g, n, h);
            },
            secp256r1: function () {
                var curve = new ECCurve(
                        BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16),
                        BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16),
                        BigInteger("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16));

                var g = new ECPoint(curve,
                        curve.fromBigInteger(BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16)),
                        curve.fromBigInteger(BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16))
                );
                var n = BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16);
                var h = BigInteger.ONE;
                return new X9ECParameters(curve, g, n, h);
            }
        };


        function ECPoint(curve,x,y,z) {
            this.curve = curve;
            this.x = x;
            this.y = y;
            if(z == null) {
                this.z = BigInteger.ONE;
            }
            else {
                this.z = z;
            }
            this.zinv = null;
        }
        ECPoint.prototype = {
            multiply: function (k) {
                if (this.isInfinity()) return this;
                if (k.signum() == 0) return this.curve.getInfinity();

                var e = k;
                var h = e.multiply(new BigInteger("3"));

                var neg = this.negate();
                var R = this;

                var i;
                for (i = h.bitLength() - 2; i > 0; --i) {
                    R = R.twice();

                    var hBit = h.testBit(i);
                    var eBit = e.testBit(i);

                    if (hBit != eBit) {
                        R = R.add(hBit ? this : neg);
                    }
                }

                return R;
            },
            add: function(b) {
                if (this.isInfinity()) return b;
                if (b.isInfinity()) return this;

                var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
                var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);

                if (BigInteger.ZERO.equals(v)) {
                    if (BigInteger.ZERO.equals(u)) {
                        return this.twice();
                    }
                    return this.curve.getInfinity();
                }

                var THREE = new BigInteger("3");
                var x1 = this.x.toBigInteger();
                var y1 = this.y.toBigInteger();
                var x2 = b.x.toBigInteger();
                var y2 = b.y.toBigInteger();

                var v2 = v.square();
                var v3 = v2.multiply(v);
                var x1v2 = x1.multiply(v2);
                var zu2 = u.square().multiply(this.z);

                var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
                var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
                var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);

                return new ECPoint(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
            },
            twice: function() {
                if (this.isInfinity()) return this;
                if (this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();

                var THREE = new BigInteger("3");
                var x1 = this.x.toBigInteger();
                var y1 = this.y.toBigInteger();

                var y1z1 = y1.multiply(this.z);
                var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
                var a = this.curve.a.toBigInteger();

                var w = x1.square().multiply(THREE);
                if (!BigInteger.ZERO.equals(a)) {
                    w = w.add(this.z.square().multiply(a));
                }
                w = w.mod(this.curve.q);
                var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
                var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
                var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);

                return new ECPoint(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
            },
            negate: function() {
                return new ECPoint(this.curve, this.x, this.y.negate(), this.z);
            },
            isInfinity: function() {
                if ((this.x == null) && (this.y == null)) return true;
                return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
            },
            getX: function(){
                if(this.zinv == null) {
                    this.zinv = this.z.modInverse(this.curve.q);
                }
                return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q));
            },
            getY: function(){
                if(this.zinv == null) {
                    this.zinv = this.z.modInverse(this.curve.q);
                }
                return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q));
            }
        };

        function ECCurve(q,a,b) {
            this.q = q;
            this.a = this.fromBigInteger(a);
            this.b = this.fromBigInteger(b);
            this.infinity = new ECPoint(this, null, null);
        }
        ECCurve.prototype = {
            fromBigInteger: function(x){
                return new ECFieldElement(this.q, x);
            },
            getInfinity: function(){
                return this.infinity;
            }
        };

        function ECFieldElement(q,x) {
            this.x = x;
            this.q = q;
        }
        ECFieldElement.prototype = {
            negate: function(){
                return new ECFieldElement(this.q, this.x.negate().mod(this.q));
            },
            toBigInteger: function(){
                return this.x;
            }
        };


        var X9EC = X9ECTypes[X9ECName]();
        var point = X9EC.g.multiply(privateKeyBignum);

        this.getPoint = function () {
            return point;
        };

        return this;

    }

    global['EllipticCurve'] = EllipticCurve;

})(this);

(function (global) {

    /* SHA256 hashing from Digest.js
     https://github.com/jcsirot/digest.js
     digest.js is released under the terms of the GNU GENERAL PUBLIC LICENSE Version 3
     */

    var utils = {
        add: function (x, y) {
            return (x + y) & 0xFFFFFFFF;
        },

        add3: function (a, b, c) {
            return (a + b + c) & 0xFFFFFFFF;
        },

        add4: function (a, b, c, d) {
            return (a + b + c + d) & 0xFFFFFFFF;
        },

        add5: function (a, b, c, d, e) {
            return (a + b + c + d + e) & 0xFFFFFFFF;
        },

        leftrot: function (x, n) {
            return ((x << n) | (x >>> (32 - n))) & 0xFFFFFFFF;
        },

        rightrot: function (x, n) {
            return ((x >>> n) | (x << (32 - n))) & 0xFFFFFFFF;
        }
    };

    function sha256Engine() {
    }

    sha256Engine.prototype.processBlock = function (input) {
        var RR = utils.rightrot;
        var ADD = utils.add;
        var ADD3 = utils.add3;
        var ADD4 = utils.add4;
        var ADD5 = utils.add5;

        var data = new DataView(input.buffer, 0, input.length);
        var A = this.current[0];
        var B = this.current[1];
        var C = this.current[2];
        var D = this.current[3];
        var E = this.current[4];
        var F = this.current[5];
        var G = this.current[6];
        var H = this.current[7];
        var T1;
        var W0, W1, W2, W3, W4, W5, W6, W7;
        var W8, W9, Wa, Wb, Wc, Wd, We, Wf;

        W0 = data.getUint32(0);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0x428A2F98, W0);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W1 = data.getUint32(4);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0x71374491, W1);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        W2 = data.getUint32(8);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0xB5C0FBCF, W2);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        W3 = data.getUint32(12);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0xE9B5DBA5, W3);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        W4 = data.getUint32(16);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x3956C25B, W4);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        W5 = data.getUint32(20);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0x59F111F1, W5);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        W6 = data.getUint32(24);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x923F82A4, W6);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        W7 = data.getUint32(28);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0xAB1C5ED5, W7);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W8 = data.getUint32(32);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0xD807AA98, W8);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W9 = data.getUint32(36);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0x12835B01, W9);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        Wa = data.getUint32(40);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0x243185BE, Wa);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        Wb = data.getUint32(44);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0x550C7DC3, Wb);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        Wc = data.getUint32(48);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x72BE5D74, Wc);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        Wd = data.getUint32(52);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0x80DEB1FE, Wd);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        We = data.getUint32(56);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x9BDC06A7, We);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        Wf = data.getUint32(60);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0xC19BF174, Wf);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W0 = ADD4(RR(We, 17) ^ RR(We, 19) ^ (We >>> 10), W9, RR(W1, 7) ^ RR(W1, 18) ^ (W1 >>> 3), W0);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0xE49B69C1, W0);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W1 = ADD4(RR(Wf, 17) ^ RR(Wf, 19) ^ (Wf >>> 10), Wa, RR(W2, 7) ^ RR(W2, 18) ^ (W2 >>> 3), W1);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0xEFBE4786, W1);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        W2 = ADD4(RR(W0, 17) ^ RR(W0, 19) ^ (W0 >>> 10), Wb, RR(W3, 7) ^ RR(W3, 18) ^ (W3 >>> 3), W2);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0x0FC19DC6, W2);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        W3 = ADD4(RR(W1, 17) ^ RR(W1, 19) ^ (W1 >>> 10), Wc, RR(W4, 7) ^ RR(W4, 18) ^ (W4 >>> 3), W3);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0x240CA1CC, W3);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        W4 = ADD4(RR(W2, 17) ^ RR(W2, 19) ^ (W2 >>> 10), Wd, RR(W5, 7) ^ RR(W5, 18) ^ (W5 >>> 3), W4);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x2DE92C6F, W4);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        W5 = ADD4(RR(W3, 17) ^ RR(W3, 19) ^ (W3 >>> 10), We, RR(W6, 7) ^ RR(W6, 18) ^ (W6 >>> 3), W5);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0x4A7484AA, W5);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        W6 = ADD4(RR(W4, 17) ^ RR(W4, 19) ^ (W4 >>> 10), Wf, RR(W7, 7) ^ RR(W7, 18) ^ (W7 >>> 3), W6);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x5CB0A9DC, W6);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        W7 = ADD4(RR(W5, 17) ^ RR(W5, 19) ^ (W5 >>> 10), W0, RR(W8, 7) ^ RR(W8, 18) ^ (W8 >>> 3), W7);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0x76F988DA, W7);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W8 = ADD4(RR(W6, 17) ^ RR(W6, 19) ^ (W6 >>> 10), W1, RR(W9, 7) ^ RR(W9, 18) ^ (W9 >>> 3), W8);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0x983E5152, W8);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W9 = ADD4(RR(W7, 17) ^ RR(W7, 19) ^ (W7 >>> 10), W2, RR(Wa, 7) ^ RR(Wa, 18) ^ (Wa >>> 3), W9);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0xA831C66D, W9);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        Wa = ADD4(RR(W8, 17) ^ RR(W8, 19) ^ (W8 >>> 10), W3, RR(Wb, 7) ^ RR(Wb, 18) ^ (Wb >>> 3), Wa);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0xB00327C8, Wa);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        Wb = ADD4(RR(W9, 17) ^ RR(W9, 19) ^ (W9 >>> 10), W4, RR(Wc, 7) ^ RR(Wc, 18) ^ (Wc >>> 3), Wb);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0xBF597FC7, Wb);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        Wc = ADD4(RR(Wa, 17) ^ RR(Wa, 19) ^ (Wa >>> 10), W5, RR(Wd, 7) ^ RR(Wd, 18) ^ (Wd >>> 3), Wc);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0xC6E00BF3, Wc);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        Wd = ADD4(RR(Wb, 17) ^ RR(Wb, 19) ^ (Wb >>> 10), W6, RR(We, 7) ^ RR(We, 18) ^ (We >>> 3), Wd);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0xD5A79147, Wd);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        We = ADD4(RR(Wc, 17) ^ RR(Wc, 19) ^ (Wc >>> 10), W7, RR(Wf, 7) ^ RR(Wf, 18) ^ (Wf >>> 3), We);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x06CA6351, We);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        Wf = ADD4(RR(Wd, 17) ^ RR(Wd, 19) ^ (Wd >>> 10), W8, RR(W0, 7) ^ RR(W0, 18) ^ (W0 >>> 3), Wf);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0x14292967, Wf);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W0 = ADD4(RR(We, 17) ^ RR(We, 19) ^ (We >>> 10), W9, RR(W1, 7) ^ RR(W1, 18) ^ (W1 >>> 3), W0);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0x27B70A85, W0);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W1 = ADD4(RR(Wf, 17) ^ RR(Wf, 19) ^ (Wf >>> 10), Wa, RR(W2, 7) ^ RR(W2, 18) ^ (W2 >>> 3), W1);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0x2E1B2138, W1);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        W2 = ADD4(RR(W0, 17) ^ RR(W0, 19) ^ (W0 >>> 10), Wb, RR(W3, 7) ^ RR(W3, 18) ^ (W3 >>> 3), W2);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0x4D2C6DFC, W2);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        W3 = ADD4(RR(W1, 17) ^ RR(W1, 19) ^ (W1 >>> 10), Wc, RR(W4, 7) ^ RR(W4, 18) ^ (W4 >>> 3), W3);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0x53380D13, W3);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        W4 = ADD4(RR(W2, 17) ^ RR(W2, 19) ^ (W2 >>> 10), Wd, RR(W5, 7) ^ RR(W5, 18) ^ (W5 >>> 3), W4);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x650A7354, W4);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        W5 = ADD4(RR(W3, 17) ^ RR(W3, 19) ^ (W3 >>> 10), We, RR(W6, 7) ^ RR(W6, 18) ^ (W6 >>> 3), W5);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0x766A0ABB, W5);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        W6 = ADD4(RR(W4, 17) ^ RR(W4, 19) ^ (W4 >>> 10), Wf, RR(W7, 7) ^ RR(W7, 18) ^ (W7 >>> 3), W6);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x81C2C92E, W6);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        W7 = ADD4(RR(W5, 17) ^ RR(W5, 19) ^ (W5 >>> 10), W0, RR(W8, 7) ^ RR(W8, 18) ^ (W8 >>> 3), W7);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0x92722C85, W7);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W8 = ADD4(RR(W6, 17) ^ RR(W6, 19) ^ (W6 >>> 10), W1, RR(W9, 7) ^ RR(W9, 18) ^ (W9 >>> 3), W8);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0xA2BFE8A1, W8);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W9 = ADD4(RR(W7, 17) ^ RR(W7, 19) ^ (W7 >>> 10), W2, RR(Wa, 7) ^ RR(Wa, 18) ^ (Wa >>> 3), W9);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0xA81A664B, W9);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        Wa = ADD4(RR(W8, 17) ^ RR(W8, 19) ^ (W8 >>> 10), W3, RR(Wb, 7) ^ RR(Wb, 18) ^ (Wb >>> 3), Wa);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0xC24B8B70, Wa);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        Wb = ADD4(RR(W9, 17) ^ RR(W9, 19) ^ (W9 >>> 10), W4, RR(Wc, 7) ^ RR(Wc, 18) ^ (Wc >>> 3), Wb);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0xC76C51A3, Wb);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        Wc = ADD4(RR(Wa, 17) ^ RR(Wa, 19) ^ (Wa >>> 10), W5, RR(Wd, 7) ^ RR(Wd, 18) ^ (Wd >>> 3), Wc);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0xD192E819, Wc);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        Wd = ADD4(RR(Wb, 17) ^ RR(Wb, 19) ^ (Wb >>> 10), W6, RR(We, 7) ^ RR(We, 18) ^ (We >>> 3), Wd);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0xD6990624, Wd);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        We = ADD4(RR(Wc, 17) ^ RR(Wc, 19) ^ (Wc >>> 10), W7, RR(Wf, 7) ^ RR(Wf, 18) ^ (Wf >>> 3), We);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0xF40E3585, We);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        Wf = ADD4(RR(Wd, 17) ^ RR(Wd, 19) ^ (Wd >>> 10), W8, RR(W0, 7) ^ RR(W0, 18) ^ (W0 >>> 3), Wf);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0x106AA070, Wf);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W0 = ADD4(RR(We, 17) ^ RR(We, 19) ^ (We >>> 10), W9, RR(W1, 7) ^ RR(W1, 18) ^ (W1 >>> 3), W0);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0x19A4C116, W0);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W1 = ADD4(RR(Wf, 17) ^ RR(Wf, 19) ^ (Wf >>> 10), Wa, RR(W2, 7) ^ RR(W2, 18) ^ (W2 >>> 3), W1);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0x1E376C08, W1);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        W2 = ADD4(RR(W0, 17) ^ RR(W0, 19) ^ (W0 >>> 10), Wb, RR(W3, 7) ^ RR(W3, 18) ^ (W3 >>> 3), W2);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0x2748774C, W2);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        W3 = ADD4(RR(W1, 17) ^ RR(W1, 19) ^ (W1 >>> 10), Wc, RR(W4, 7) ^ RR(W4, 18) ^ (W4 >>> 3), W3);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0x34B0BCB5, W3);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        W4 = ADD4(RR(W2, 17) ^ RR(W2, 19) ^ (W2 >>> 10), Wd, RR(W5, 7) ^ RR(W5, 18) ^ (W5 >>> 3), W4);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x391C0CB3, W4);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        W5 = ADD4(RR(W3, 17) ^ RR(W3, 19) ^ (W3 >>> 10), We, RR(W6, 7) ^ RR(W6, 18) ^ (W6 >>> 3), W5);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0x4ED8AA4A, W5);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        W6 = ADD4(RR(W4, 17) ^ RR(W4, 19) ^ (W4 >>> 10), Wf, RR(W7, 7) ^ RR(W7, 18) ^ (W7 >>> 3), W6);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0x5B9CCA4F, W6);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        W7 = ADD4(RR(W5, 17) ^ RR(W5, 19) ^ (W5 >>> 10), W0, RR(W8, 7) ^ RR(W8, 18) ^ (W8 >>> 3), W7);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0x682E6FF3, W7);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);
        W8 = ADD4(RR(W6, 17) ^ RR(W6, 19) ^ (W6 >>> 10), W1, RR(W9, 7) ^ RR(W9, 18) ^ (W9 >>> 3), W8);
        T1 = ADD5(H, RR(E, 6) ^ RR(E, 11) ^ RR(E, 25), (E & F) ^ (~E & G), 0x748F82EE, W8);
        H = ADD3(T1, RR(A, 2) ^ RR(A, 13) ^ RR(A, 22), (A & B) ^ (B & C) ^ (A & C));
        D = ADD(D, T1);
        W9 = ADD4(RR(W7, 17) ^ RR(W7, 19) ^ (W7 >>> 10), W2, RR(Wa, 7) ^ RR(Wa, 18) ^ (Wa >>> 3), W9);
        T1 = ADD5(G, RR(D, 6) ^ RR(D, 11) ^ RR(D, 25), (D & E) ^ (~D & F), 0x78A5636F, W9);
        G = ADD3(T1, RR(H, 2) ^ RR(H, 13) ^ RR(H, 22), (H & A) ^ (A & B) ^ (H & B));
        C = ADD(C, T1);
        Wa = ADD4(RR(W8, 17) ^ RR(W8, 19) ^ (W8 >>> 10), W3, RR(Wb, 7) ^ RR(Wb, 18) ^ (Wb >>> 3), Wa);
        T1 = ADD5(F, RR(C, 6) ^ RR(C, 11) ^ RR(C, 25), (C & D) ^ (~C & E), 0x84C87814, Wa);
        F = ADD3(T1, RR(G, 2) ^ RR(G, 13) ^ RR(G, 22), (G & H) ^ (H & A) ^ (G & A));
        B = ADD(B, T1);
        Wb = ADD4(RR(W9, 17) ^ RR(W9, 19) ^ (W9 >>> 10), W4, RR(Wc, 7) ^ RR(Wc, 18) ^ (Wc >>> 3), Wb);
        T1 = ADD5(E, RR(B, 6) ^ RR(B, 11) ^ RR(B, 25), (B & C) ^ (~B & D), 0x8CC70208, Wb);
        E = ADD3(T1, RR(F, 2) ^ RR(F, 13) ^ RR(F, 22), (F & G) ^ (G & H) ^ (F & H));
        A = ADD(A, T1);
        Wc = ADD4(RR(Wa, 17) ^ RR(Wa, 19) ^ (Wa >>> 10), W5, RR(Wd, 7) ^ RR(Wd, 18) ^ (Wd >>> 3), Wc);
        T1 = ADD5(D, RR(A, 6) ^ RR(A, 11) ^ RR(A, 25), (A & B) ^ (~A & C), 0x90BEFFFA, Wc);
        D = ADD3(T1, RR(E, 2) ^ RR(E, 13) ^ RR(E, 22), (E & F) ^ (F & G) ^ (E & G));
        H = ADD(H, T1);
        Wd = ADD4(RR(Wb, 17) ^ RR(Wb, 19) ^ (Wb >>> 10), W6, RR(We, 7) ^ RR(We, 18) ^ (We >>> 3), Wd);
        T1 = ADD5(C, RR(H, 6) ^ RR(H, 11) ^ RR(H, 25), (H & A) ^ (~H & B), 0xA4506CEB, Wd);
        C = ADD3(T1, RR(D, 2) ^ RR(D, 13) ^ RR(D, 22), (D & E) ^ (E & F) ^ (D & F));
        G = ADD(G, T1);
        We = ADD4(RR(Wc, 17) ^ RR(Wc, 19) ^ (Wc >>> 10), W7, RR(Wf, 7) ^ RR(Wf, 18) ^ (Wf >>> 3), We);
        T1 = ADD5(B, RR(G, 6) ^ RR(G, 11) ^ RR(G, 25), (G & H) ^ (~G & A), 0xBEF9A3F7, We);
        B = ADD3(T1, RR(C, 2) ^ RR(C, 13) ^ RR(C, 22), (C & D) ^ (D & E) ^ (C & E));
        F = ADD(F, T1);
        Wf = ADD4(RR(Wd, 17) ^ RR(Wd, 19) ^ (Wd >>> 10), W8, RR(W0, 7) ^ RR(W0, 18) ^ (W0 >>> 3), Wf);
        T1 = ADD5(A, RR(F, 6) ^ RR(F, 11) ^ RR(F, 25), (F & G) ^ (~F & H), 0xC67178F2, Wf);
        A = ADD3(T1, RR(B, 2) ^ RR(B, 13) ^ RR(B, 22), (B & C) ^ (C & D) ^ (B & D));
        E = ADD(E, T1);

        this.current[0] += A;
        this.current[1] += B;
        this.current[2] += C;
        this.current[3] += D;
        this.current[4] += E;
        this.current[5] += F;
        this.current[6] += G;
        this.current[7] += H;
        this.currentLen += 64;
    };

    sha256Engine.prototype.doPadding = function () {
        var datalen = (this.inLen + this.currentLen) * 8;
        var msw = 0; // FIXME
        var lsw = datalen & 0xFFFFFFFF;
        var zeros = this.inLen <= 55 ? 55 - this.inLen : 119 - this.inLen;
        var pad = new Uint8Array(new ArrayBuffer(zeros + 1 + 8));
        pad[0] = 0x80;
        pad[pad.length - 1] = lsw & 0xFF;
        pad[pad.length - 2] = (lsw >>> 8) & 0xFF;
        pad[pad.length - 3] = (lsw >>> 16) & 0xFF;
        pad[pad.length - 4] = (lsw >>> 24) & 0xFF;
        pad[pad.length - 5] = msw & 0xFF;
        pad[pad.length - 6] = (msw >>> 8) & 0xFF;
        pad[pad.length - 7] = (msw >>> 16) & 0xFF;
        pad[pad.length - 8] = (msw >>> 24) & 0xFF;
        return pad;
    };

    sha256Engine.prototype.getDigest = function () {
        var rv = new Uint8Array(new ArrayBuffer(32));
        rv[3] = this.current[0] & 0xFF;
        rv[2] = (this.current[0] >>> 8) & 0xFF;
        rv[1] = (this.current[0] >>> 16) & 0xFF;
        rv[0] = (this.current[0] >>> 24) & 0xFF;
        rv[7] = this.current[1] & 0xFF;
        rv[6] = (this.current[1] >>> 8) & 0xFF;
        rv[5] = (this.current[1] >>> 16) & 0xFF;
        rv[4] = (this.current[1] >>> 24) & 0xFF;
        rv[11] = this.current[2] & 0xFF;
        rv[10] = (this.current[2] >>> 8) & 0xFF;
        rv[9] = (this.current[2] >>> 16) & 0xFF;
        rv[8] = (this.current[2] >>> 24) & 0xFF;
        rv[15] = this.current[3] & 0xFF;
        rv[14] = (this.current[3] >>> 8) & 0xFF;
        rv[13] = (this.current[3] >>> 16) & 0xFF;
        rv[12] = (this.current[3] >>> 24) & 0xFF;
        rv[19] = this.current[4] & 0xFF;
        rv[18] = (this.current[4] >>> 8) & 0xFF;
        rv[17] = (this.current[4] >>> 16) & 0xFF;
        rv[16] = (this.current[4] >>> 24) & 0xFF;
        rv[23] = this.current[5] & 0xFF;
        rv[22] = (this.current[5] >>> 8) & 0xFF;
        rv[21] = (this.current[5] >>> 16) & 0xFF;
        rv[20] = (this.current[5] >>> 24) & 0xFF;
        rv[27] = this.current[6] & 0xFF;
        rv[26] = (this.current[6] >>> 8) & 0xFF;
        rv[25] = (this.current[6] >>> 16) & 0xFF;
        rv[24] = (this.current[6] >>> 24) & 0xFF;
        rv[31] = this.current[7] & 0xFF;
        rv[30] = (this.current[7] >>> 8) & 0xFF;
        rv[29] = (this.current[7] >>> 16) & 0xFF;
        rv[28] = (this.current[7] >>> 24) & 0xFF;
        return rv;
    };

    sha256Engine.prototype.reset = function () {
        this.currentLen = 0;
        this.inLen = 0;
        this.current = new Uint32Array(new ArrayBuffer(32));
        this.current[0] = 0x6A09E667;
        this.current[1] = 0xBB67AE85;
        this.current[2] = 0x3C6EF372;
        this.current[3] = 0xA54FF53A;
        this.current[4] = 0x510E527F;
        this.current[5] = 0x9B05688C;
        this.current[6] = 0x1F83D9AB;
        this.current[7] = 0x5BE0CD19;
    };

    sha256Engine.prototype.blockLen = 64;
    sha256Engine.prototype.digestLen = 32;

    var dg = function (Constructor) {
        var update = function (input) {
            var len = input.length;
            var offset = 0;
            while (len > 0) {
                var copyLen = this.blockLen - this.inLen;
                if (copyLen > len) {
                    copyLen = len;
                }
                var tmpInput = input.subarray(offset, offset + copyLen);
                this.inbuf.set(tmpInput, this.inLen);
                offset += copyLen;
                len -= copyLen;
                this.inLen += copyLen;
                if (this.inLen === this.blockLen) {
                    this.processBlock(this.inbuf);
                    this.inLen = 0;
                }
            }
        };

        var finalize = function () {
            var padding = this.doPadding();
            this.update(padding);
            var result = this.getDigest();
            this.reset();
            return result;
        };

        var engine = (function () {
            if (!Constructor) {
                throw "Unsupported algorithm: " + Constructor.toString();
            }
            Constructor.prototype.update = update;
            Constructor.prototype.finalize = finalize;
            var engine = new Constructor();
            engine.inbuf = new Uint8Array(new ArrayBuffer(engine.blockLen));
            engine.reset();
            return engine;
        }());

        return {
            update: function (input) {
                engine.update(input);
            },

            finalize: function () {
                return engine.finalize();
            },

            digest: function (input) {
                this.update(input);
                return engine.finalize();
            },

            reset: function () {
                engine.reset();
            },

            digestLength: function () {
                return engine.digestLen;
            }
        };
    };

    global['sha256'] = function (data) {
        return dg(sha256Engine).digest(data);
    };

})(this);

(function (global) {

    /*
     CryptoJS v3.1.2
     code.google.com/p/crypto-js
     (c) 2009-2013 by Jeff Mott. All rights reserved.
     code.google.com/p/crypto-js/wiki/License
     */
    /** @preserve
     (c) 2012 by Cédric Mesnil. All rights reserved.

     Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

     - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */

    // Constants table
    var zl = [
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
        7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
        3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
        1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
        4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13];
    var zr = [
        5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
        6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
        15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
        8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
        12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11];
    var sl = [
        11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
        7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
        11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
        11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
        9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ];
    var sr = [
        8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
        9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
        9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
        15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
        8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ];

    var hl = [ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E];
    var hr = [ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000];

    var bytesToWords = function (bytes) {
        var words = [];
        for (var i = 0, b = 0; i < bytes.length; i++, b += 8) {
            words[b >>> 5] |= bytes[i] << (24 - b % 32);
        }
        return words;
    };

    var wordsToBytes = function (words) {
        var bytes = [];
        for (var b = 0; b < words.length * 32; b += 8) {
            bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
        }
        return bytes;
    };

    var processBlock = function (H, M, offset) {

        // Swap endian
        for (var i = 0; i < 16; i++) {
            var offset_i = offset + i;
            var M_offset_i = M[offset_i];

            // Swap
            M[offset_i] = (
                    (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
                    (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
                    );
        }

        // Working variables
        var al, bl, cl, dl, el;
        var ar, br, cr, dr, er;

        ar = al = H[0];
        br = bl = H[1];
        cr = cl = H[2];
        dr = dl = H[3];
        er = el = H[4];
        // Computation
        var t;
        for (var i = 0; i < 80; i += 1) {
            t = (al + M[offset + zl[i]]) | 0;
            if (i < 16) {
                t += f1(bl, cl, dl) + hl[0];
            } else if (i < 32) {
                t += f2(bl, cl, dl) + hl[1];
            } else if (i < 48) {
                t += f3(bl, cl, dl) + hl[2];
            } else if (i < 64) {
                t += f4(bl, cl, dl) + hl[3];
            } else {// if (i<80) {
                t += f5(bl, cl, dl) + hl[4];
            }
            t = t | 0;
            t = rotl(t, sl[i]);
            t = (t + el) | 0;
            al = el;
            el = dl;
            dl = rotl(cl, 10);
            cl = bl;
            bl = t;

            t = (ar + M[offset + zr[i]]) | 0;
            if (i < 16) {
                t += f5(br, cr, dr) + hr[0];
            } else if (i < 32) {
                t += f4(br, cr, dr) + hr[1];
            } else if (i < 48) {
                t += f3(br, cr, dr) + hr[2];
            } else if (i < 64) {
                t += f2(br, cr, dr) + hr[3];
            } else {// if (i<80) {
                t += f1(br, cr, dr) + hr[4];
            }
            t = t | 0;
            t = rotl(t, sr[i]);
            t = (t + er) | 0;
            ar = er;
            er = dr;
            dr = rotl(cr, 10);
            cr = br;
            br = t;
        }
        // Intermediate hash value
        t = (H[1] + cl + dr) | 0;
        H[1] = (H[2] + dl + er) | 0;
        H[2] = (H[3] + el + ar) | 0;
        H[3] = (H[4] + al + br) | 0;
        H[4] = (H[0] + bl + cr) | 0;
        H[0] = t;
    };

    function f1(x, y, z) {
        return ((x) ^ (y) ^ (z));
    }

    function f2(x, y, z) {
        return (((x) & (y)) | ((~x) & (z)));
    }

    function f3(x, y, z) {
        return (((x) | (~(y))) ^ (z));
    }

    function f4(x, y, z) {
        return (((x) & (z)) | ((y) & (~(z))));
    }

    function f5(x, y, z) {
        return ((x) ^ ((y) | (~(z))));
    }

    function rotl(x, n) {
        return (x << n) | (x >>> (32 - n));
    }

    function ripemd160(message) {
        var H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];

        var m = bytesToWords(message);

        var nBitsLeft = message.length * 8;
        var nBitsTotal = message.length * 8;

        // Add padding
        m[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
        m[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
                (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) |
                (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00)
                );

        for (var i = 0; i < m.length; i += 16) {
            processBlock(H, m, i);
        }

        // Swap endian
        for (var i = 0; i < 5; i++) {
            // Shortcut
            var H_i = H[i];

            // Swap
            H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
                    (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);
        }

        var digestbytes = wordsToBytes(H);
        return digestbytes;
    }

    global['ripemd160'] = ripemd160;

})(this);







(function (global) {



// JavaScript engine analysis
    var canary = 0xdeadbeefcafe;
    var j_lm = ((canary & 0xffffff) == 0xefcafe);

// (public) Constructor
    function BigInteger(a, b, c) {
        if (!(this instanceof BigInteger)) {
            return new BigInteger(a, b, c);
        }

        if (a != null) {
            if ("number" == typeof a) this.fromNumber(a, b, c);
            else if (b == null && "string" != typeof a) this.fromString(a, 256);
            else this.fromString(a, b);
        }
    }

    var proto = BigInteger.prototype;

// return new, unset BigInteger
    function nbi() {
        return new BigInteger(null);
    }

// Bits per digit
    var dbits;

// am: Compute w_j += (x*this_i), propagate carries,
// c is initial carry, returns final carry.
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
// We need to select the fastest one that works in this environment.

// am1: use a single mult and divide to get the high bits,
// max digit bits should be 26 because
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
    function am1(i, x, w, j, c, n) {
        while (--n >= 0) {
            var v = x * this[i++] + w[j] + c;
            c = Math.floor(v / 0x4000000);
            w[j++] = v & 0x3ffffff;
        }
        return c;
    }

// am2 avoids a big mult-and-extract completely.
// Max digit bits should be <= 30 because we do bitwise ops
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
    function am2(i, x, w, j, c, n) {
        var xl = x & 0x7fff, xh = x >> 15;
        while (--n >= 0) {
            var l = this[i] & 0x7fff;
            var h = this[i++] >> 15;
            var m = xh * l + h * xl;
            l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
            c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
            w[j++] = l & 0x3fffffff;
        }
        return c;
    }

// Alternately, set max digit bits to 28 since some
// browsers slow down when dealing with 32-bit numbers.
    function am3(i, x, w, j, c, n) {
        var xl = x & 0x3fff, xh = x >> 14;
        while (--n >= 0) {
            var l = this[i] & 0x3fff;
            var h = this[i++] >> 14;
            var m = xh * l + h * xl;
            l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
            c = (l >> 28) + (m >> 14) + xh * h;
            w[j++] = l & 0xfffffff;
        }
        return c;
    }

// wtf?
    BigInteger.prototype.am = am1;
    dbits = 26;

    /*
     if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
     BigInteger.prototype.am = am2;
     dbits = 30;
     }
     else if(j_lm && (navigator.appName != "Netscape")) {
     BigInteger.prototype.am = am1;
     dbits = 26;
     }
     else { // Mozilla/Netscape seems to prefer am3
     BigInteger.prototype.am = am3;
     dbits = 28;
     }
     */

    BigInteger.prototype.DB = dbits;
    BigInteger.prototype.DM = ((1 << dbits) - 1);
    var DV = BigInteger.prototype.DV = (1 << dbits);

    var BI_FP = 52;
    BigInteger.prototype.FV = Math.pow(2, BI_FP);
    BigInteger.prototype.F1 = BI_FP - dbits;
    BigInteger.prototype.F2 = 2 * dbits - BI_FP;

// Digit conversions
    var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
    var BI_RC = new Array();
    var rr, vv;
    rr = "0".charCodeAt(0);
    for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
    rr = "a".charCodeAt(0);
    for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
    rr = "A".charCodeAt(0);
    for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;

    function int2char(n) {
        return BI_RM.charAt(n);
    }

    function intAt(s, i) {
        var c = BI_RC[s.charCodeAt(i)];
        return (c == null) ? -1 : c;
    }

// (protected) copy this to r
    function bnpCopyTo(r) {
        for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
        r.t = this.t;
        r.s = this.s;
    }

// (protected) set from integer value x, -DV <= x < DV
    function bnpFromInt(x) {
        this.t = 1;
        this.s = (x < 0) ? -1 : 0;
        if (x > 0) this[0] = x;
        else if (x < -1) this[0] = x + DV;
        else this.t = 0;
    }

// return bigint initialized to value
    function nbv(i) {
        var r = nbi();
        r.fromInt(i);
        return r;
    }

// (protected) set from string and radix
    function bnpFromString(s, b) {
        var self = this;

        var k;
        if (b == 16) k = 4;
        else if (b == 8) k = 3;
        else if (b == 256) k = 8; // byte array
        else if (b == 2) k = 1;
        else if (b == 32) k = 5;
        else if (b == 4) k = 2;
        else {
            self.fromRadix(s, b);
            return;
        }
        self.t = 0;
        self.s = 0;
        var i = s.length, mi = false, sh = 0;
        while (--i >= 0) {
            var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
            if (x < 0) {
                if (s.charAt(i) == "-") mi = true;
                continue;
            }
            mi = false;
            if (sh == 0)
                self[self.t++] = x;
            else if (sh + k > self.DB) {
                self[self.t - 1] |= (x & ((1 << (self.DB - sh)) - 1)) << sh;
                self[self.t++] = (x >> (self.DB - sh));
            }
            else
                self[self.t - 1] |= x << sh;
            sh += k;
            if (sh >= self.DB) sh -= self.DB;
        }
        if (k == 8 && (s[0] & 0x80) != 0) {
            self.s = -1;
            if (sh > 0) self[self.t - 1] |= ((1 << (self.DB - sh)) - 1) << sh;
        }
        self.clamp();
        if (mi) BigInteger.ZERO.subTo(self, self);
    }

// (protected) clamp off excess high words
    function bnpClamp() {
        var c = this.s & this.DM;
        while (this.t > 0 && this[this.t - 1] == c) --this.t;
    }

// (public) return string representation in given radix
    function bnToString(b) {
        var self = this;
        if (self.s < 0) return "-" + self.negate().toString(b);
        var k;
        if (b == 16) k = 4;
        else if (b == 8) k = 3;
        else if (b == 2) k = 1;
        else if (b == 32) k = 5;
        else if (b == 4) k = 2;
        else return self.toRadix(b);
        var km = (1 << k) - 1, d, m = false, r = "", i = self.t;
        var p = self.DB - (i * self.DB) % k;
        if (i-- > 0) {
            if (p < self.DB && (d = self[i] >> p) > 0) {
                m = true;
                r = int2char(d);
            }
            while (i >= 0) {
                if (p < k) {
                    d = (self[i] & ((1 << p) - 1)) << (k - p);
                    d |= self[--i] >> (p += self.DB - k);
                }
                else {
                    d = (self[i] >> (p -= k)) & km;
                    if (p <= 0) {
                        p += self.DB;
                        --i;
                    }
                }
                if (d > 0) m = true;
                if (m) r += int2char(d);
            }
        }
        return m ? r : "0";
    }

// (public) -this
    function bnNegate() {
        var r = nbi();
        BigInteger.ZERO.subTo(this, r);
        return r;
    }

// (public) |this|
    function bnAbs() {
        return (this.s < 0) ? this.negate() : this;
    }

// (public) return + if this > a, - if this < a, 0 if equal
    function bnCompareTo(a) {
        var r = this.s - a.s;
        if (r != 0) return r;
        var i = this.t;
        r = i - a.t;
        if (r != 0) return (this.s < 0) ? -r : r;
        while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
        return 0;
    }

// returns bit length of the integer x
    function nbits(x) {
        var r = 1, t;
        if ((t = x >>> 16) != 0) {
            x = t;
            r += 16;
        }
        if ((t = x >> 8) != 0) {
            x = t;
            r += 8;
        }
        if ((t = x >> 4) != 0) {
            x = t;
            r += 4;
        }
        if ((t = x >> 2) != 0) {
            x = t;
            r += 2;
        }
        if ((t = x >> 1) != 0) {
            x = t;
            r += 1;
        }
        return r;
    }

// (public) return the number of bits in "this"
    function bnBitLength() {
        if (this.t <= 0) return 0;
        return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
    }

// (protected) r = this << n*DB
    function bnpDLShiftTo(n, r) {
        var i;
        for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
        for (i = n - 1; i >= 0; --i) r[i] = 0;
        r.t = this.t + n;
        r.s = this.s;
    }

// (protected) r = this >> n*DB
    function bnpDRShiftTo(n, r) {
        for (var i = n; i < this.t; ++i) r[i - n] = this[i];
        r.t = Math.max(this.t - n, 0);
        r.s = this.s;
    }

// (protected) r = this << n
    function bnpLShiftTo(n, r) {
        var self = this;
        var bs = n % self.DB;
        var cbs = self.DB - bs;
        var bm = (1 << cbs) - 1;
        var ds = Math.floor(n / self.DB), c = (self.s << bs) & self.DM, i;
        for (i = self.t - 1; i >= 0; --i) {
            r[i + ds + 1] = (self[i] >> cbs) | c;
            c = (self[i] & bm) << bs;
        }
        for (i = ds - 1; i >= 0; --i) r[i] = 0;
        r[ds] = c;
        r.t = self.t + ds + 1;
        r.s = self.s;
        r.clamp();
    }

// (protected) r = this >> n
    function bnpRShiftTo(n, r) {
        var self = this;
        r.s = self.s;
        var ds = Math.floor(n / self.DB);
        if (ds >= self.t) {
            r.t = 0;
            return;
        }
        var bs = n % self.DB;
        var cbs = self.DB - bs;
        var bm = (1 << bs) - 1;
        r[0] = self[ds] >> bs;
        for (var i = ds + 1; i < self.t; ++i) {
            r[i - ds - 1] |= (self[i] & bm) << cbs;
            r[i - ds] = self[i] >> bs;
        }
        if (bs > 0) r[self.t - ds - 1] |= (self.s & bm) << cbs;
        r.t = self.t - ds;
        r.clamp();
    }

// (protected) r = this - a
    function bnpSubTo(a, r) {
        var self = this;
        var i = 0, c = 0, m = Math.min(a.t, self.t);
        while (i < m) {
            c += self[i] - a[i];
            r[i++] = c & self.DM;
            c >>= self.DB;
        }
        if (a.t < self.t) {
            c -= a.s;
            while (i < self.t) {
                c += self[i];
                r[i++] = c & self.DM;
                c >>= self.DB;
            }
            c += self.s;
        }
        else {
            c += self.s;
            while (i < a.t) {
                c -= a[i];
                r[i++] = c & self.DM;
                c >>= self.DB;
            }
            c -= a.s;
        }
        r.s = (c < 0) ? -1 : 0;
        if (c < -1) r[i++] = self.DV + c;
        else if (c > 0) r[i++] = c;
        r.t = i;
        r.clamp();
    }

// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
    function bnpMultiplyTo(a, r) {
        var x = this.abs(), y = a.abs();
        var i = x.t;
        r.t = i + y.t;
        while (--i >= 0) r[i] = 0;
        for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
        r.s = 0;
        r.clamp();
        if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
    }

// (protected) r = this^2, r != this (HAC 14.16)
    function bnpSquareTo(r) {
        var x = this.abs();
        var i = r.t = 2 * x.t;
        while (--i >= 0) r[i] = 0;
        for (i = 0; i < x.t - 1; ++i) {
            var c = x.am(i, x[i], r, 2 * i, 0, 1);
            if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
                r[i + x.t] -= x.DV;
                r[i + x.t + 1] = 1;
            }
        }
        if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
        r.s = 0;
        r.clamp();
    }

// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
// r != q, this != m.  q or r may be null.
    function bnpDivRemTo(m, q, r) {
        var self = this;
        var pm = m.abs();
        if (pm.t <= 0) return;
        var pt = self.abs();
        if (pt.t < pm.t) {
            if (q != null) q.fromInt(0);
            if (r != null) self.copyTo(r);
            return;
        }
        if (r == null) r = nbi();
        var y = nbi(), ts = self.s, ms = m.s;
        var nsh = self.DB - nbits(pm[pm.t - 1]);  // normalize modulus
        if (nsh > 0) {
            pm.lShiftTo(nsh, y);
            pt.lShiftTo(nsh, r);
        }
        else {
            pm.copyTo(y);
            pt.copyTo(r);
        }
        var ys = y.t;
        var y0 = y[ys - 1];
        if (y0 == 0) return;
        var yt = y0 * (1 << self.F1) + ((ys > 1) ? y[ys - 2] >> self.F2 : 0);
        var d1 = self.FV / yt, d2 = (1 << self.F1) / yt, e = 1 << self.F2;
        var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
        y.dlShiftTo(j, t);
        if (r.compareTo(t) >= 0) {
            r[r.t++] = 1;
            r.subTo(t, r);
        }
        BigInteger.ONE.dlShiftTo(ys, t);
        t.subTo(y, y); // "negative" y so we can replace sub with am later
        while (y.t < ys) y[y.t++] = 0;
        while (--j >= 0) {
            // Estimate quotient digit
            var qd = (r[--i] == y0) ? self.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
            if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) {  // Try it out
                y.dlShiftTo(j, t);
                r.subTo(t, r);
                while (r[i] < --qd) r.subTo(t, r);
            }
        }
        if (q != null) {
            r.drShiftTo(ys, q);
            if (ts != ms) BigInteger.ZERO.subTo(q, q);
        }
        r.t = ys;
        r.clamp();
        if (nsh > 0) r.rShiftTo(nsh, r);    // Denormalize remainder
        if (ts < 0) BigInteger.ZERO.subTo(r, r);
    }

// (public) this mod a
    function bnMod(a) {
        var r = nbi();
        this.abs().divRemTo(a, null, r);
        if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
        return r;
    }

// Modular reduction using "classic" algorithm
    function Classic(m) {
        this.m = m;
    }

    function cConvert(x) {
        if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
        else return x;
    }

    function cRevert(x) {
        return x;
    }

    function cReduce(x) {
        x.divRemTo(this.m, null, x);
    }

    function cMulTo(x, y, r) {
        x.multiplyTo(y, r);
        this.reduce(r);
    }

    function cSqrTo(x, r) {
        x.squareTo(r);
        this.reduce(r);
    }

    Classic.prototype.convert = cConvert;
    Classic.prototype.revert = cRevert;
    Classic.prototype.reduce = cReduce;
    Classic.prototype.mulTo = cMulTo;
    Classic.prototype.sqrTo = cSqrTo;

// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
// justification:
//         xy == 1 (mod m)
//         xy =  1+km
//   xy(2-xy) = (1+km)(1-km)
// x[y(2-xy)] = 1-k^2m^2
// x[y(2-xy)] == 1 (mod m^2)
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
// JS multiply "overflows" differently from C/C++, so care is needed here.
    function bnpInvDigit() {
        if (this.t < 1) return 0;
        var x = this[0];
        if ((x & 1) == 0) return 0;
        var y = x & 3;      // y == 1/x mod 2^2
        y = (y * (2 - (x & 0xf) * y)) & 0xf;    // y == 1/x mod 2^4
        y = (y * (2 - (x & 0xff) * y)) & 0xff;  // y == 1/x mod 2^8
        y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff;   // y == 1/x mod 2^16
        // last step - calculate inverse mod DV directly;
        // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
        y = (y * (2 - x * y % this.DV)) % this.DV;      // y == 1/x mod 2^dbits
        // we really want the negative inverse, and -DV < y < DV
        return (y > 0) ? this.DV - y : -y;
    }

// Montgomery reduction
    function Montgomery(m) {
        this.m = m;
        this.mp = m.invDigit();
        this.mpl = this.mp & 0x7fff;
        this.mph = this.mp >> 15;
        this.um = (1 << (m.DB - 15)) - 1;
        this.mt2 = 2 * m.t;
    }

// xR mod m
    function montConvert(x) {
        var r = nbi();
        x.abs().dlShiftTo(this.m.t, r);
        r.divRemTo(this.m, null, r);
        if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
        return r;
    }

// x/R mod m
    function montRevert(x) {
        var r = nbi();
        x.copyTo(r);
        this.reduce(r);
        return r;
    }

// x = x/R mod m (HAC 14.32)
    function montReduce(x) {
        while (x.t <= this.mt2)    // pad x so am has enough room later
            x[x.t++] = 0;
        for (var i = 0; i < this.m.t; ++i) {
            // faster way of calculating u0 = x[i]*mp mod DV
            var j = x[i] & 0x7fff;
            var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
            // use am to combine the multiply-shift-add into one call
            j = i + this.m.t;
            x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
            // propagate carry
            while (x[j] >= x.DV) {
                x[j] -= x.DV;
                x[++j]++;
            }
        }
        x.clamp();
        x.drShiftTo(this.m.t, x);
        if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
    }

// r = "x^2/R mod m"; x != r
    function montSqrTo(x, r) {
        x.squareTo(r);
        this.reduce(r);
    }

// r = "xy/R mod m"; x,y != r
    function montMulTo(x, y, r) {
        x.multiplyTo(y, r);
        this.reduce(r);
    }

    Montgomery.prototype.convert = montConvert;
    Montgomery.prototype.revert = montRevert;
    Montgomery.prototype.reduce = montReduce;
    Montgomery.prototype.mulTo = montMulTo;
    Montgomery.prototype.sqrTo = montSqrTo;

// (protected) true iff this is even
    function bnpIsEven() {
        return ((this.t > 0) ? (this[0] & 1) : this.s) == 0;
    }

// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
    function bnpExp(e, z) {
        if (e > 0xffffffff || e < 1) return BigInteger.ONE;
        var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
        g.copyTo(r);
        while (--i >= 0) {
            z.sqrTo(r, r2);
            if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
            else {
                var t = r;
                r = r2;
                r2 = t;
            }
        }
        return z.revert(r);
    }

// (public) this^e % m, 0 <= e < 2^32
    function bnModPowInt(e, m) {
        var z;
        if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
        return this.exp(e, z);
    }

// protected
    proto.copyTo = bnpCopyTo;
    proto.fromInt = bnpFromInt;
    proto.fromString = bnpFromString;
    proto.clamp = bnpClamp;
    proto.dlShiftTo = bnpDLShiftTo;
    proto.drShiftTo = bnpDRShiftTo;
    proto.lShiftTo = bnpLShiftTo;
    proto.rShiftTo = bnpRShiftTo;
    proto.subTo = bnpSubTo;
    proto.multiplyTo = bnpMultiplyTo;
    proto.squareTo = bnpSquareTo;
    proto.divRemTo = bnpDivRemTo;
    proto.invDigit = bnpInvDigit;
    proto.isEven = bnpIsEven;
    proto.exp = bnpExp;

// public
    proto.toString = bnToString;
    proto.negate = bnNegate;
    proto.abs = bnAbs;
    proto.compareTo = bnCompareTo;
    proto.bitLength = bnBitLength;
    proto.mod = bnMod;
    proto.modPowInt = bnModPowInt;

//// jsbn2

    function nbi() {
        return new BigInteger(null);
    }

// (public)
    function bnClone() {
        var r = nbi();
        this.copyTo(r);
        return r;
    }

// (public) return value as integer
    function bnIntValue() {
        if (this.s < 0) {
            if (this.t == 1) return this[0] - this.DV;
            else if (this.t == 0) return -1;
        }
        else if (this.t == 1) return this[0];
        else if (this.t == 0) return 0;
        // assumes 16 < DB < 32
        return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
    }

// (public) return value as byte
    function bnByteValue() {
        return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
    }

// (public) return value as short (assumes DB>=16)
    function bnShortValue() {
        return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
    }

// (protected) return x s.t. r^x < DV
    function bnpChunkSize(r) {
        return Math.floor(Math.LN2 * this.DB / Math.log(r));
    }

// (public) 0 if this == 0, 1 if this > 0
    function bnSigNum() {
        if (this.s < 0) return -1;
        else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
        else return 1;
    }

// (protected) convert to radix string
    function bnpToRadix(b) {
        if (b == null) b = 10;
        if (this.signum() == 0 || b < 2 || b > 36) return "0";
        var cs = this.chunkSize(b);
        var a = Math.pow(b, cs);
        var d = nbv(a), y = nbi(), z = nbi(), r = "";
        this.divRemTo(d, y, z);
        while (y.signum() > 0) {
            r = (a + z.intValue()).toString(b).substr(1) + r;
            y.divRemTo(d, y, z);
        }
        return z.intValue().toString(b) + r;
    }

// (protected) convert from radix string
    function bnpFromRadix(s, b) {
        var self = this;
        self.fromInt(0);
        if (b == null) b = 10;
        var cs = self.chunkSize(b);
        var d = Math.pow(b, cs), mi = false, j = 0, w = 0;
        for (var i = 0; i < s.length; ++i) {
            var x = intAt(s, i);
            if (x < 0) {
                if (s.charAt(i) == "-" && self.signum() == 0) mi = true;
                continue;
            }
            w = b * w + x;
            if (++j >= cs) {
                self.dMultiply(d);
                self.dAddOffset(w, 0);
                j = 0;
                w = 0;
            }
        }
        if (j > 0) {
            self.dMultiply(Math.pow(b, j));
            self.dAddOffset(w, 0);
        }
        if (mi) BigInteger.ZERO.subTo(self, self);
    }

// (protected) alternate constructor
    function bnpFromNumber(a, b, c) {
        var self = this;
        if ("number" == typeof b) {
            // new BigInteger(int,int,RNG)
            if (a < 2) self.fromInt(1);
            else {
                self.fromNumber(a, c);
                if (!self.testBit(a - 1))    // force MSB set
                    self.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, self);
                if (self.isEven()) self.dAddOffset(1, 0); // force odd
                while (!self.isProbablePrime(b)) {
                    self.dAddOffset(2, 0);
                    if (self.bitLength() > a) self.subTo(BigInteger.ONE.shiftLeft(a - 1), self);
                }
            }
        }
        else {
            // new BigInteger(int,RNG)
            var x = new Array(), t = a & 7;
            x.length = (a >> 3) + 1;
            b.nextBytes(x);
            if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0;
            self.fromString(x, 256);
        }
    }

// (public) convert to bigendian byte array
    function bnToByteArray() {
        var self = this;
        var i = self.t, r = new Array();
        r[0] = self.s;
        var p = self.DB - (i * self.DB) % 8, d, k = 0;
        if (i-- > 0) {
            if (p < self.DB && (d = self[i] >> p) != (self.s & self.DM) >> p)
                r[k++] = d | (self.s << (self.DB - p));
            while (i >= 0) {
                if (p < 8) {
                    d = (self[i] & ((1 << p) - 1)) << (8 - p);
                    d |= self[--i] >> (p += self.DB - 8);
                }
                else {
                    d = (self[i] >> (p -= 8)) & 0xff;
                    if (p <= 0) {
                        p += self.DB;
                        --i;
                    }
                }
                if ((d & 0x80) != 0) d |= -256;
                if (k === 0 && (self.s & 0x80) != (d & 0x80)) ++k;
                if (k > 0 || d != self.s) r[k++] = d;
            }
        }
        return r;
    }

    function bnEquals(a) {
        return(this.compareTo(a) == 0);
    }

    function bnMin(a) {
        return(this.compareTo(a) < 0) ? this : a;
    }

    function bnMax(a) {
        return(this.compareTo(a) > 0) ? this : a;
    }

// (protected) r = this op a (bitwise)
    function bnpBitwiseTo(a, op, r) {
        var self = this;
        var i, f, m = Math.min(a.t, self.t);
        for (i = 0; i < m; ++i) r[i] = op(self[i], a[i]);
        if (a.t < self.t) {
            f = a.s & self.DM;
            for (i = m; i < self.t; ++i) r[i] = op(self[i], f);
            r.t = self.t;
        }
        else {
            f = self.s & self.DM;
            for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
            r.t = a.t;
        }
        r.s = op(self.s, a.s);
        r.clamp();
    }

// (public) this & a
    function op_and(x, y) {
        return x & y;
    }

    function bnAnd(a) {
        var r = nbi();
        this.bitwiseTo(a, op_and, r);
        return r;
    }

// (public) this | a
    function op_or(x, y) {
        return x | y;
    }

    function bnOr(a) {
        var r = nbi();
        this.bitwiseTo(a, op_or, r);
        return r;
    }

// (public) this ^ a
    function op_xor(x, y) {
        return x ^ y;
    }

    function bnXor(a) {
        var r = nbi();
        this.bitwiseTo(a, op_xor, r);
        return r;
    }

// (public) this & ~a
    function op_andnot(x, y) {
        return x & ~y;
    }

    function bnAndNot(a) {
        var r = nbi();
        this.bitwiseTo(a, op_andnot, r);
        return r;
    }

// (public) ~this
    function bnNot() {
        var r = nbi();
        for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
        r.t = this.t;
        r.s = ~this.s;
        return r;
    }

// (public) this << n
    function bnShiftLeft(n) {
        var r = nbi();
        if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
        return r;
    }

// (public) this >> n
    function bnShiftRight(n) {
        var r = nbi();
        if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
        return r;
    }

// return index of lowest 1-bit in x, x < 2^31
    function lbit(x) {
        if (x == 0) return -1;
        var r = 0;
        if ((x & 0xffff) == 0) {
            x >>= 16;
            r += 16;
        }
        if ((x & 0xff) == 0) {
            x >>= 8;
            r += 8;
        }
        if ((x & 0xf) == 0) {
            x >>= 4;
            r += 4;
        }
        if ((x & 3) == 0) {
            x >>= 2;
            r += 2;
        }
        if ((x & 1) == 0) ++r;
        return r;
    }

// (public) returns index of lowest 1-bit (or -1 if none)
    function bnGetLowestSetBit() {
        for (var i = 0; i < this.t; ++i)
            if (this[i] != 0) return i * this.DB + lbit(this[i]);
        if (this.s < 0) return this.t * this.DB;
        return -1;
    }

// return number of 1 bits in x
    function cbit(x) {
        var r = 0;
        while (x != 0) {
            x &= x - 1;
            ++r;
        }
        return r;
    }

// (public) return number of set bits
    function bnBitCount() {
        var r = 0, x = this.s & this.DM;
        for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
        return r;
    }

// (public) true iff nth bit is set
    function bnTestBit(n) {
        var j = Math.floor(n / this.DB);
        if (j >= this.t) return(this.s != 0);
        return((this[j] & (1 << (n % this.DB))) != 0);
    }

// (protected) this op (1<<n)
    function bnpChangeBit(n, op) {
        var r = BigInteger.ONE.shiftLeft(n);
        this.bitwiseTo(r, op, r);
        return r;
    }

// (public) this | (1<<n)
    function bnSetBit(n) {
        return this.changeBit(n, op_or);
    }

// (public) this & ~(1<<n)
    function bnClearBit(n) {
        return this.changeBit(n, op_andnot);
    }

// (public) this ^ (1<<n)
    function bnFlipBit(n) {
        return this.changeBit(n, op_xor);
    }

// (protected) r = this + a
    function bnpAddTo(a, r) {
        var self = this;

        var i = 0, c = 0, m = Math.min(a.t, self.t);
        while (i < m) {
            c += self[i] + a[i];
            r[i++] = c & self.DM;
            c >>= self.DB;
        }
        if (a.t < self.t) {
            c += a.s;
            while (i < self.t) {
                c += self[i];
                r[i++] = c & self.DM;
                c >>= self.DB;
            }
            c += self.s;
        }
        else {
            c += self.s;
            while (i < a.t) {
                c += a[i];
                r[i++] = c & self.DM;
                c >>= self.DB;
            }
            c += a.s;
        }
        r.s = (c < 0) ? -1 : 0;
        if (c > 0) r[i++] = c;
        else if (c < -1) r[i++] = self.DV + c;
        r.t = i;
        r.clamp();
    }

// (public) this + a
    function bnAdd(a) {
        var r = nbi();
        this.addTo(a, r);
        return r;
    }

// (public) this - a
    function bnSubtract(a) {
        var r = nbi();
        this.subTo(a, r);
        return r;
    }

// (public) this * a
    function bnMultiply(a) {
        var r = nbi();
        this.multiplyTo(a, r);
        return r;
    }

// (public) this^2
    function bnSquare() {
        var r = nbi();
        this.squareTo(r);
        return r;
    }

// (public) this / a
    function bnDivide(a) {
        var r = nbi();
        this.divRemTo(a, r, null);
        return r;
    }

// (public) this % a
    function bnRemainder(a) {
        var r = nbi();
        this.divRemTo(a, null, r);
        return r;
    }

// (public) [this/a,this%a]
    function bnDivideAndRemainder(a) {
        var q = nbi(), r = nbi();
        this.divRemTo(a, q, r);
        return new Array(q, r);
    }

// (protected) this *= n, this >= 0, 1 < n < DV
    function bnpDMultiply(n) {
        this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
        ++this.t;
        this.clamp();
    }

// (protected) this += n << w words, this >= 0
    function bnpDAddOffset(n, w) {
        if (n == 0) return;
        while (this.t <= w) this[this.t++] = 0;
        this[w] += n;
        while (this[w] >= this.DV) {
            this[w] -= this.DV;
            if (++w >= this.t) this[this.t++] = 0;
            ++this[w];
        }
    }

// A "null" reducer
    function NullExp() {
    }

    function nNop(x) {
        return x;
    }

    function nMulTo(x, y, r) {
        x.multiplyTo(y, r);
    }

    function nSqrTo(x, r) {
        x.squareTo(r);
    }

    NullExp.prototype.convert = nNop;
    NullExp.prototype.revert = nNop;
    NullExp.prototype.mulTo = nMulTo;
    NullExp.prototype.sqrTo = nSqrTo;

// (public) this^e
    function bnPow(e) {
        return this.exp(e, new NullExp());
    }

// (protected) r = lower n words of "this * a", a.t <= n
// "this" should be the larger one if appropriate.
    function bnpMultiplyLowerTo(a, n, r) {
        var i = Math.min(this.t + a.t, n);
        r.s = 0; // assumes a,this >= 0
        r.t = i;
        while (i > 0) r[--i] = 0;
        var j;
        for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
        for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
        r.clamp();
    }

// (protected) r = "this * a" without lower n words, n > 0
// "this" should be the larger one if appropriate.
    function bnpMultiplyUpperTo(a, n, r) {
        --n;
        var i = r.t = this.t + a.t - n;
        r.s = 0; // assumes a,this >= 0
        while (--i >= 0) r[i] = 0;
        for (i = Math.max(n - this.t, 0); i < a.t; ++i)
            r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
        r.clamp();
        r.drShiftTo(1, r);
    }

// Barrett modular reduction
    function Barrett(m) {
        // setup Barrett
        this.r2 = nbi();
        this.q3 = nbi();
        BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
        this.mu = this.r2.divide(m);
        this.m = m;
    }

    function barrettConvert(x) {
        if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
        else if (x.compareTo(this.m) < 0) return x;
        else {
            var r = nbi();
            x.copyTo(r);
            this.reduce(r);
            return r;
        }
    }

    function barrettRevert(x) {
        return x;
    }

// x = x mod m (HAC 14.42)
    function barrettReduce(x) {
        var self = this;
        x.drShiftTo(self.m.t - 1, self.r2);
        if (x.t > self.m.t + 1) {
            x.t = self.m.t + 1;
            x.clamp();
        }
        self.mu.multiplyUpperTo(self.r2, self.m.t + 1, self.q3);
        self.m.multiplyLowerTo(self.q3, self.m.t + 1, self.r2);
        while (x.compareTo(self.r2) < 0) x.dAddOffset(1, self.m.t + 1);
        x.subTo(self.r2, x);
        while (x.compareTo(self.m) >= 0) x.subTo(self.m, x);
    }

// r = x^2 mod m; x != r
    function barrettSqrTo(x, r) {
        x.squareTo(r);
        this.reduce(r);
    }

// r = x*y mod m; x,y != r
    function barrettMulTo(x, y, r) {
        x.multiplyTo(y, r);
        this.reduce(r);
    }

    Barrett.prototype.convert = barrettConvert;
    Barrett.prototype.revert = barrettRevert;
    Barrett.prototype.reduce = barrettReduce;
    Barrett.prototype.mulTo = barrettMulTo;
    Barrett.prototype.sqrTo = barrettSqrTo;

// (public) this^e % m (HAC 14.85)
    function bnModPow(e, m) {
        var i = e.bitLength(), k, r = nbv(1), z;
        if (i <= 0) return r;
        else if (i < 18) k = 1;
        else if (i < 48) k = 3;
        else if (i < 144) k = 4;
        else if (i < 768) k = 5;
        else k = 6;
        if (i < 8)
            z = new Classic(m);
        else if (m.isEven())
            z = new Barrett(m);
        else
            z = new Montgomery(m);

        // precomputation
        var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1;
        g[1] = z.convert(this);
        if (k > 1) {
            var g2 = nbi();
            z.sqrTo(g[1], g2);
            while (n <= km) {
                g[n] = nbi();
                z.mulTo(g2, g[n - 2], g[n]);
                n += 2;
            }
        }

        var j = e.t - 1, w, is1 = true, r2 = nbi(), t;
        i = nbits(e[j]) - 1;
        while (j >= 0) {
            if (i >= k1) w = (e[j] >> (i - k1)) & km;
            else {
                w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
                if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
            }

            n = k;
            while ((w & 1) == 0) {
                w >>= 1;
                --n;
            }
            if ((i -= n) < 0) {
                i += this.DB;
                --j;
            }
            if (is1) {   // ret == 1, don't bother squaring or multiplying it
                g[w].copyTo(r);
                is1 = false;
            }
            else {
                while (n > 1) {
                    z.sqrTo(r, r2);
                    z.sqrTo(r2, r);
                    n -= 2;
                }
                if (n > 0) z.sqrTo(r, r2); else {
                    t = r;
                    r = r2;
                    r2 = t;
                }
                z.mulTo(r2, g[w], r);
            }

            while (j >= 0 && (e[j] & (1 << i)) == 0) {
                z.sqrTo(r, r2);
                t = r;
                r = r2;
                r2 = t;
                if (--i < 0) {
                    i = this.DB - 1;
                    --j;
                }
            }
        }
        return z.revert(r);
    }

// (public) gcd(this,a) (HAC 14.54)
    function bnGCD(a) {
        var x = (this.s < 0) ? this.negate() : this.clone();
        var y = (a.s < 0) ? a.negate() : a.clone();
        if (x.compareTo(y) < 0) {
            var t = x;
            x = y;
            y = t;
        }
        var i = x.getLowestSetBit(), g = y.getLowestSetBit();
        if (g < 0) return x;
        if (i < g) g = i;
        if (g > 0) {
            x.rShiftTo(g, x);
            y.rShiftTo(g, y);
        }
        while (x.signum() > 0) {
            if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
            if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
            if (x.compareTo(y) >= 0) {
                x.subTo(y, x);
                x.rShiftTo(1, x);
            }
            else {
                y.subTo(x, y);
                y.rShiftTo(1, y);
            }
        }
        if (g > 0) y.lShiftTo(g, y);
        return y;
    }

// (protected) this % n, n < 2^26
    function bnpModInt(n) {
        if (n <= 0) return 0;
        var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0;
        if (this.t > 0)
            if (d == 0) r = this[0] % n;
            else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
        return r;
    }

// (public) 1/this % m (HAC 14.61)
    function bnModInverse(m) {
        var ac = m.isEven();
        if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
        var u = m.clone(), v = this.clone();
        var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
        while (u.signum() != 0) {
            while (u.isEven()) {
                u.rShiftTo(1, u);
                if (ac) {
                    if (!a.isEven() || !b.isEven()) {
                        a.addTo(this, a);
                        b.subTo(m, b);
                    }
                    a.rShiftTo(1, a);
                }
                else if (!b.isEven()) b.subTo(m, b);
                b.rShiftTo(1, b);
            }
            while (v.isEven()) {
                v.rShiftTo(1, v);
                if (ac) {
                    if (!c.isEven() || !d.isEven()) {
                        c.addTo(this, c);
                        d.subTo(m, d);
                    }
                    c.rShiftTo(1, c);
                }
                else if (!d.isEven()) d.subTo(m, d);
                d.rShiftTo(1, d);
            }
            if (u.compareTo(v) >= 0) {
                u.subTo(v, u);
                if (ac) a.subTo(c, a);
                b.subTo(d, b);
            }
            else {
                v.subTo(u, v);
                if (ac) c.subTo(a, c);
                d.subTo(b, d);
            }
        }
        if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
        if (d.compareTo(m) >= 0) return d.subtract(m);
        if (d.signum() < 0) d.addTo(m, d); else return d;
        if (d.signum() < 0) return d.add(m); else return d;
    }

// protected
    proto.chunkSize = bnpChunkSize;
    proto.toRadix = bnpToRadix;
    proto.fromRadix = bnpFromRadix;
    proto.fromNumber = bnpFromNumber;
    proto.bitwiseTo = bnpBitwiseTo;
    proto.changeBit = bnpChangeBit;
    proto.addTo = bnpAddTo;
    proto.dMultiply = bnpDMultiply;
    proto.dAddOffset = bnpDAddOffset;
    proto.multiplyLowerTo = bnpMultiplyLowerTo;
    proto.multiplyUpperTo = bnpMultiplyUpperTo;
    proto.modInt = bnpModInt;

// public
    proto.clone = bnClone;
    proto.intValue = bnIntValue;
    proto.byteValue = bnByteValue;
    proto.shortValue = bnShortValue;
    proto.signum = bnSigNum;
    proto.toByteArray = bnToByteArray;
    proto.equals = bnEquals;
    proto.min = bnMin;
    proto.max = bnMax;
    proto.and = bnAnd;
    proto.or = bnOr;
    proto.xor = bnXor;
    proto.andNot = bnAndNot;
    proto.not = bnNot;
    proto.shiftLeft = bnShiftLeft;
    proto.shiftRight = bnShiftRight;
    proto.getLowestSetBit = bnGetLowestSetBit;
    proto.bitCount = bnBitCount;
    proto.testBit = bnTestBit;
    proto.setBit = bnSetBit;
    proto.clearBit = bnClearBit;
    proto.flipBit = bnFlipBit;
    proto.add = bnAdd;
    proto.subtract = bnSubtract;
    proto.multiply = bnMultiply;
    proto.divide = bnDivide;
    proto.remainder = bnRemainder;
    proto.divideAndRemainder = bnDivideAndRemainder;
    proto.modPow = bnModPow;
    proto.modInverse = bnModInverse;
    proto.pow = bnPow;
    proto.gcd = bnGCD;

// JSBN-specific extension
    proto.square = bnSquare;

// BigInteger interfaces not implemented in jsbn:

// BigInteger(int signum, byte[] magnitude)
// double doubleValue()
// float floatValue()
// int hashCode()
// long longValue()
// static BigInteger valueOf(long val)

// "constants"
    BigInteger.ZERO = nbv(0);
    BigInteger.ONE = nbv(1);
    BigInteger.valueOf = nbv;

    global['BigInteger'] = BigInteger;

})(this);


</script>

</body>

</html>